package dao

import (
	"errors"
	"fitness/internal/entity/system"
	"fitness/pkg/utils"
	"fmt"
	"github.com/duke-git/lancet/v2/convertor"
	"go.uber.org/zap"
	"gorm.io/gorm"
	"strconv"
	"strings"
	"time"
)

type SysDictDao struct {
	DB             *gorm.DB
	SysDictItemDao *SysDictItemDao
	Log            *zap.Logger
}

func NewSysDictDao(DB *gorm.DB, SysDictItemDao *SysDictItemDao, Log *zap.Logger) *SysDictDao {
	return &SysDictDao{
		DB:             DB,
		SysDictItemDao: SysDictItemDao,
		Log:            Log,
	}
}

func (sysDictDao *SysDictDao) ListDictItemsByCode(code string) []utils.Option[string] {
	var dict system.SysDict
	sysDictDao.DB.Select("id").Where("code = ?", code).First(&dict)
	if dict.ID == 0 {
		return make([]utils.Option[string], 0)
	}

	list := sysDictDao.SysDictItemDao.List(dict.ID)
	var options []utils.Option[string]
	for _, item := range list {
		var option utils.Option[string]
		option.Value = item.Value
		option.Label = item.Name
		options = append(options, option)
	}
	return options
}

func (sysDictDao *SysDictDao) GetDictPage(queryParams system.SysDictPageQuery) (utils.Page[system.DictPageVO], error) {

	sql := `SELECT
            t1.id,
            t1.name,
            t1.code,
            t1.status
        FROM
            sys_dict t1 where     t1.is_deleted = 0`

	where := ""
	if queryParams.PageQuery.Keywords != nil && *queryParams.PageQuery.Keywords != "" {
		where = ` and (
		          t1.name LIKE '%` + *queryParams.PageQuery.Keywords + `%'
		           OR t1.code LIKE '%` + *queryParams.PageQuery.Keywords + `%'
		           )`
	}

	sql = sql + where + " ORDER BY  t1.create_time DESC"
	var totalRecords int64
	page := *queryParams.PageQuery.PageNum      // 当前页码
	pageSize := *queryParams.PageQuery.PageSize // 每页数据量

	// 计算偏移量
	offset := (page - 1) * pageSize
	var dicts = make([]system.SysDict, 0)

	var res utils.Page[system.DictPageVO]

	err := sysDictDao.DB.Raw(sql).Offset(int(offset)).Limit(int(pageSize)).Find(&dicts).Error
	if err != nil {
		return res, err
	}
	// 获取总记录数
	err = sysDictDao.DB.Model(&system.SysDict{}).Count(&totalRecords).Error
	if err != nil {
		return res, err
	}
	//总数
	res.Total = totalRecords
	//数据
	var dictVos []system.DictPageVO

	for _, dict := range dicts {
		list := sysDictDao.SysDictItemDao.List(dict.ID)
		var dictVo system.DictPageVO
		dictVo.ID = dict.ID
		dictVo.Name = dict.Name
		dictVo.Code = dict.Code
		dictVo.Status = dict.Status
		dictVo.DictItems = list
		dictVos = append(dictVos, dictVo)
	}
	res.List = dictVos
	return res, nil
}

func (sysDictDao *SysDictDao) GetDictForm(id uint64) (system.DictPageVO, error) {
	var dict system.SysDict

	err := sysDictDao.DB.Model(&system.SysDict{}).Where("id = ?", id).Find(&dict).Error
	var dictVo system.DictPageVO
	if err != nil {
		return dictVo, err
	}
	list := sysDictDao.SysDictItemDao.List(dict.ID)
	dictVo.ID = dict.ID
	dictVo.Name = dict.Name
	dictVo.Code = dict.Code
	dictVo.Status = dict.Status
	dictVo.DictItems = list
	return dictVo, nil
}

func (sysDictDao *SysDictDao) SaveDict(pageVO system.DictPageVO) (b bool, e error) {
	//开启一个事务
	tx := sysDictDao.DB.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback() // 捕获panic，确保回滚
			fmt.Println("Recovered in safeCall", r)
			b = false
			e = errors.New("执行报错")
		}
	}()
	if tx.Error != nil {
		// 如果事务开始失败，则直接返回错误
		return false, tx.Error
	}
	var i int64
	err := tx.Model(&system.SysDict{}).Where("code = ?", pageVO.Code).Count(&i).Error
	if err != nil {
		tx.Rollback()
		return false, err
	}
	if i > 0 {
		return false, errors.New("字典编码已存在")
	}
	var dict system.SysDict
	dict.ID = pageVO.ID
	dict.Name = pageVO.Name
	dict.Code = pageVO.Code
	dict.Status = pageVO.Status
	dict.CreateTime = time.Now()
	err = tx.Model(&system.SysDict{}).Create(&dict).Error
	if err != nil {
		tx.Rollback()
		return false, err
	}
	items := pageVO.DictItems
	for _, item := range items {
		item.DictId = dict.ID
		err := tx.Model(&system.SysDictItem{}).Create(&item).Error
		if err != nil {
			tx.Rollback()
			return false, err
		}
	}
	tx.Commit()
	return true, nil
}

func (sysDictDao *SysDictDao) DeleteDict(idStr string) (bool, error) {
	if idStr == "" {
		return false, errors.New("至少需要一个参数")
	}
	split := strings.Split(idStr, ",")
	var list []uint64
	for _, val := range split {
		end, _ := strconv.ParseUint(val, 10, 64)
		list = append(list, end)
	}
	db := sysDictDao.DB.Begin()
	for _, id := range list {
		err := db.Delete(&system.SysDict{}, "id = ?", id).Error
		if err != nil {
			db.Rollback()
			return false, err
		}
		err = db.Delete(&system.SysDictItem{}, "dict_id = ?", id).Error
		if err != nil {
			db.Rollback()
			return false, err
		}
	}
	db.Commit()
	return true, nil
}

func (sysDictDao *SysDictDao) UpdateDict(id uint64, pageVO system.DictForm) (b bool, e error) {
	//开启一个事务
	tx := sysDictDao.DB.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback() // 捕获panic，确保回滚
			fmt.Println("Recovered in safeCall", r)
			b = false
			e = errors.New("执行报错")
		}
	}()

	if tx.Error != nil {
		// 如果事务开始失败，则直接返回错误
		return false, tx.Error
	}
	var i int64
	err := tx.Model(&system.SysDict{}).Where("code = ? and id <> ?", pageVO.Code, id).Count(&i).Error
	if err != nil {
		tx.Rollback()
		return false, err
	}
	if i > 0 {
		return false, errors.New("字典编码已存在")
	}
	dict := system.SysDict{
		ID:         pageVO.ID,
		Name:       pageVO.Name,
		Code:       pageVO.Code,
		Status:     pageVO.Status,
		UpdateTime: time.Now(),
	}
	err = tx.Model(&system.SysDict{}).Where("id = ?", pageVO.ID).Updates(dict).Error
	if err != nil {
		tx.Rollback()
		return false, err
	}
	//item全部删除再重新添加
	err = tx.Delete(&system.SysDictItem{}, "dict_id = ?", pageVO.ID).Error
	if err != nil {
		tx.Rollback()
		return false, err
	}
	items := pageVO.DictItems
	for _, item := range items {
		var dictItem system.SysDictItem
		dictItem.ID = item.ID
		dictItem.DictId = pageVO.ID
		dictItem.Name = item.Name
		dictItem.Value = item.Value
		dictItem.Status = item.Status
		sort := item.Sort
		toInt, err := convertor.ToInt(sort)
		if err != nil {
			return false, err
		}
		dictItem.Sort = int16(toInt)
		dictItem.Remark = item.Remark
		err = tx.Model(&system.SysDictItem{}).Create(&dictItem).Error
		if err != nil {
			tx.Rollback()
			return false, err
		}
	}
	tx.Commit()
	return true, nil
}
